package com.example.fp.cgc.websocket

import com.example.fp.cgc.connerlt.AlarmTask
import com.example.fp.cgc.controller.NoticeController
import com.example.fp.cgc.entity.Message
import com.example.fp.cgc.entity.Notice
import com.example.fp.cgc.util.DataUtil
import com.example.fp.cgc.util.SpringUtil
import com.google.gson.Gson
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import javax.websocket.*
import javax.websocket.server.PathParam
import javax.websocket.server.ServerEndpoint
import kotlin.collections.HashMap


@ServerEndpoint("/websocket/{data}")
@Component
open class WebSocketServer {
    var log = LoggerFactory.getLogger(WebSocketServer::class.java)


    companion object {
        val task: WebSocketServer by lazy {
            SpringUtil.getBean(WebSocketServer::class.java)
        }
        val onlineUserMap = HashMap<Int, WebSocketServer>()

        val rankViewMap = HashMap<Int, WebSocketServer>()

        @get:Synchronized
        var onlineCount = 0

        @get:Synchronized
        var rankViewCount = 0

        @Synchronized
        fun addOnlineCount() {
            onlineCount++
        }

        @Synchronized
        fun addRankViewCount() {
            rankViewCount++
        }

    }

    private var session: Session? = null

    @OnOpen
    open fun onOpen(
            @PathParam("data") data: String,
            session: Session) {
        val list = data.split("&")
        val uid = list[0].toInt()
        val type = list[1]

        this.session = session
        try {
            /**
             * @since 2020-02-28
             * 传送设置状态
             */
            val state = DataUtil.getSettingState(uid)
            this.sendMessage(state)

            when (type) {
                "index" -> {
                    onlineUserMap[uid] = this
                    addOnlineCount()
                    log.info("有新用户进行连接,当前连接数为$onlineCount")
                    /**
                     * 发送初始数据
                     * @since 2020-03-03
                     * 优化,为用户单独发送
                     */

                    AlarmTask.task.getInitData().forEach {
                        this.sendMessage(it)
                    }

                    this.sendMessage(AlarmTask.task.getMessageState(uid))
                }
                "view" -> {
                    rankViewMap[uid] = this
                    addRankViewCount()
                    log.info("有新的面板打开,当前面板数为$rankViewCount")
                    /**
                     * 发送用户列表
                     */
                    this.sendMessage(DataUtil.getUserOnlineState())
                }
            }


            /**
             * 历史消息
             */
            val mapper = AlarmTask.task.userSettingMapper
            if (mapper.getState(uid)[0].history) {
                this.sendMessage(DataUtil.getUserHistoryList(uid = uid))
            }

            /**
             * 传送关注列表
             * @since 2020-02-26
             */
            this.sendMessage(DataUtil.getFollowList(uid))

            /**
             * 发送消息盒子
             */
            this.sendMessage(DataUtil.getMessageBox(uid))

            /**
             * 获得单独发送的通知
             */
            this.sendMessage(DataUtil.getNoticeBox(uid,true))
        } catch (e: Exception) {
            log.error("WebSocker打开连接时:", e)
        }
    }


    @OnError
    open fun onError(session: Session, error: Throwable) {
        log.error("接口访问错误")
        println(error.fillInStackTrace())
    }

    @OnClose
    open fun onClose(
            @PathParam("data") data: String,
            session: Session) {
        val list = data.split("&")
        val uid = list[0].toInt()
        when (list[1]) {
            "index" -> {
                onlineCount--
                onlineUserMap.remove(uid)
                log.info("有一位用户离开,当前连接数为$onlineCount")
            }
            "view" -> {
                rankViewCount--
                rankViewMap.remove(uid)
                log.info("有一个面板离开,当前连接数为$onlineCount")
            }
        }
    }

    @OnMessage
    @Throws(IOException::class)
    open fun onMessage(message: String, session: Session) {
        val notice = Gson().fromJson(message, Notice::class.javaObjectType)

        println("notice:${notice}")

        sendNotice(notice)
    }

    @Throws(IOException::class)
    open fun sendMessage(message: String) {
        session?.basicRemote?.sendText(message)
    }

    /**
     * 对某个用户发送内容
     */
    open fun sendNotice(notice: Notice) {
        val toId = notice.toId
        val date = Date() //获得系统时间.

        val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val nowTime = sdf.format(date)
        val time = sdf.parse(nowTime)

        notice.time = time

        val data = DataUtil.getData("notice", Gson().toJson(notice))

        when (notice.scope) {
            "all" -> {
                this.sendAll("notice", data)
            }
            "single" -> {
                when {
                    onlineUserMap.containsKey(toId) -> {
                        notice.isRead = true
                        onlineUserMap[toId]?.sendMessage(data)
                    }
                    rankViewMap.containsKey(toId) -> {
                        notice.isRead = true
                        rankViewMap[toId]?.sendMessage(data)
                    }
                    else -> {
                        notice.isRead = false
                    }
                }
            }
        }
        NoticeController.noticeController.noticeMapper.insert(notice)
    }


    /**
     * 对全体用户发送更新内容
     */
    @Throws(IOException::class)
    open fun sendAll(type: String, message: String) {
        onlineUserMap.forEach { (_, server) ->
            try {
                server.sendMessage(message)
            } catch (e: Exception) {

            }
        }
        if (type == "useronline" || type == "notice") {
            rankViewMap.forEach { (_, server) ->
                try {
                    server.sendMessage(message)
                } catch (e: Exception) {

                }
            }
        }
    }
}